#include <iostream>     /// for std output
#include <getopt.h>     /// for analyze options 
#include <random>       /// for file name ramdomization
#include <fstream>      /// for create file or direcotry
#include <cstring>      /// for string operation, strlen ...
#include <sys/stat.h>   /// for mkdir function & node stat

#define VERSION "0.1"

// if is_dir = 1, the program generates directory
bool is_dir = false;

/* generate a char and return it */
char generate_char()
{
    // valid range : number = 0x30 ~ 0x39,upper case = 0x41 ~ 0x5A, lower case = 0x61 ~ 0x7A
    char rchar = 0;
    // make range dicition and generate char
    switch(std::rand() % 3)
    {
    case 0:
        rchar = std::rand() % 10 + 0x30;
        break;
    case 1:
        rchar = std::rand() % 26 + 0x41;
        break;
    case 2:
        rchar = std::rand() % 26 + 0x61; 
    } 
    
    return rchar;
}

/* create a file on file system by using CPP standard file stream */
int make_file(char *file_path)
{
    std::ofstream outfile(file_path);
    if (!outfile.is_open())
    {
        outfile.close();
        return 1;
    }

    outfile.close();
    return 0;
}

/* create a directory on file system by calling Linux system API */
int make_dir(char *dir_path)
{
    if(dir_path == nullptr)
        return 1; 
    
    return mkdir(dir_path, S_IRWXU);
}

/* output version info to standard output stream */
void print_version()
{
    std::cout << "mktemp version " << VERSION << std::endl;
    std::cout << "mktemp is coded by zplus, not the version in coreutils of GNU project." << std::endl;
    exit(0);
}

/* output help info to standard output stream*/
void print_help()
{
    std::cout << "this is help message." <<std::endl;
    exit(0);
}

/* output error message to standard error stream */
void print_error_msg(char *mesg)
{
    std::cerr << mesg;
    exit(1);
}

// how to make pointer 'path' unchangeable, and the content it points to is changeable.
/* replace 'X' with a ramdom char, this function generate the filename or directory name */
void generate_name(char * path, const int length)
{
    
    // invalid check 
    if (path == nullptr || length == 0)
        return ;

    std::srand(time(0));

    for(int index = 0; index < length; index++)
    {
        if(path[index] == 'X')
            path[index] = generate_char();
    }
}

int main (int argc, char **argv)
{
    char *path_ptr = nullptr;
    // command line argument definition 
    const option opts[] = {
        {"directory", no_argument, 0, 'd'}, 
        {"help", no_argument, 0, 'h'}, 
        {"version", no_argument, 0, 'v'}, 
        {0, 0, 0, 0}
    };
    
    // analyze command line options
    while (1)
    {
        int cmd_input = getopt_long(argc, argv,"dhv", opts, NULL);

        // cmd input analysis finished
        if (cmd_input == -1)
            break;
        
        switch(cmd_input)
        {
        case 'd':
            is_dir = true;
            break;    
        case 'h':
            print_help();
            break;
        case 'v':
            print_version();
            break;
        }
    }

    // analyze the operate target     
    if (path_ptr == nullptr && optind < argc )
        path_ptr = argv[optind];
    else 
        // print no operate target message
        return 1;

    //generating ramdom file name 
    generate_name(path_ptr, std::strlen(path_ptr)); 

    // generating file or directory on file system 
    int res = 0;
    if(is_dir)
        res = make_dir(path_ptr);
    else 
        res = make_file(path_ptr);

    std::cout << path_ptr << std::endl;
    return res;
}